#include "sdm/training.h"
#include "rna/util.h"
#include <fstream>

Training::Training(const std::vector<size_t> &layers, data_t learningRate):
    Backpropagation(new Network(layers, new LogisticActivation()), learningRate) {
    this->randomize();
}

void Training::train(const std::vector< const std::pair<data_t*, data_t*>* > &data) {
    Backpropagation::train(data);
}

void Training::randomize(){
    Backpropagation::randomize();
}

Training::OutputType Training::rate(double *output, double *target) {
    bool _output = output[0] > 0.5;
    bool _target = target[0] > 0.5;

    if ( !_output && !_target )
        return Training::VN;
    if ( !_output && _target )
        return Training::FN;
    if ( _output && !_target )
        return Training::FP;
    if ( _output && _target )
        return Training::VP;
    return Training::Undefined;
}

void Training::test(const std::vector<const std::pair<double *, double *> *> &data, std::ofstream &stream) {
    unsigned int vp, vn, fp, fn;

    vp = vn = fp = fn = 0;

    double *output;

    std::vector< const input_t* >::const_iterator iterator = data.begin(),
            end = data.end();

    while ( iterator < end ) {
        const input_t *pair = *iterator++;
        const data_t *data = pair->first;
        output = _network->feed(pair->first);

        char buffer[10];

        for ( size_t i = 0 ; i < _network->neuronsCount(0); i++ ) {
            sprintf(buffer, "%.6f", data[i]);
            stream << buffer << "\t";
        }

        sprintf(buffer, "%.6f", output[0]);
        stream << "\t|\t" << buffer << "\t";

        switch ( this->rate(output, pair->second) ) {
        case Training::VP:
            stream << "VP";
            vp++;
            break;
        case Training::VN:
            stream << "VN";
            vn++;
            break;
        case Training::FP:
            stream << "FP";
            fp++;
            break;
        case Training::FN:
            stream << "FN";
            fn++;
            break;
        case Training::Undefined:
            break;
        }
        stream << std::endl;
    }

    stream << "Verdadeiro positivo: " << vp << std::endl;
    stream << "Verdadeiro negativo: " << vn << std::endl;
    stream << "Falso positivo: " << fp << std::endl;
    stream << "Falso negativo: " << fn << std::endl;
}
